
//************************************************************************************************************************
// Author        : Partha Saradhi Sunkara                                                                     //
// COMPANY       : TATA CONSULTANCY SERVICES LTD                                                                        //
// MAIL ID       : parthasaradhi.sunkara@tcs.com                                                                           //
//                                                                                        //
// File Name     : axi_lite_master.v
// Version       : 1.0                                                                      //
// Description   : This file gives the description about                                                                //
//                 1) This is the verilog RTL code for axi_lite_master                                          //
//                                                                                                                      //
///************************************************************************************************************************
// -----------------------------------------------------------------------------
module axi_lite_master #
   (
    parameter integer C_M_AXI_ADDR_WIDTH = 32,
    parameter integer C_M_AXI_DATA_WIDTH = 32
    )
   (
  // Global Signals
  input wire M_AXI_ACLK,
  input wire M_AXI_ARESETN,
  // Write Address Channel Signals
  output wire [C_M_AXI_ADDR_WIDTH -1:0] M_AXI_AWADDR,//
  output reg M_AXI_AWVALID,//
  input wire M_AXI_AWREADY,//
  output wire [C_M_AXI_DATA_WIDTH/8-1:0] M_AXI_AWPROT,//
  // Write Data Channel Signals
  output reg [C_M_AXI_DATA_WIDTH -1:0] M_AXI_WDATA,//
  output reg [C_M_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB,//
  output reg M_AXI_WVALID,//
  input wire M_AXI_WREADY,//
  // Write Response Channel Signals
  input wire [1:0] M_AXI_BRESP,//
  input wire M_AXI_BVALID,//
  output wire M_AXI_BREADY,//
  // Read Address Channel Signals
  output wire [C_M_AXI_ADDR_WIDTH -1:0] M_AXI_ARADDR,//
  output reg M_AXI_ARVALID,//
  input wire M_AXI_ARREADY,//
  // Read Data Channel Signals
  input  wire [C_M_AXI_DATA_WIDTH -1:0] M_AXI_RDATA,//
  input  wire [1:0] M_AXI_RRESP,//
  input wire M_AXI_RVALID,//
  output reg M_AXI_RREADY,//
  // write Interface Signals
  input wire [C_M_AXI_ADDR_WIDTH -1:0] write_addr_i,
  input wire [C_M_AXI_DATA_WIDTH -1:0] write_data_i,//
  input wire write_datav_i,//
  input wire write_addrv_i,//    added this signal on 19th jan
  input wire [C_M_AXI_DATA_WIDTH/8-1:0] write_strb_i,//
  output wire [1:0] write_bresp_o,//
  output wire write_bvalid_o,//
  // read Interface Signals
  input wire read_start_i,
  input wire [C_M_AXI_ADDR_WIDTH -1:0] read_addr_i,
  input wire read_af_i,           //------------
  output reg [C_M_AXI_DATA_WIDTH -1:0] read_data_o,//
  output reg read_datav_o//
);
    
//-----------------------------------------------------------------------------
// Internal signals
//-----------------------------------------------------------------------------
  parameter       W_RESET_ST      = 0,
                  W_IDLE_ST       = 1,
                  W_GEN_VLD_ST    = 2,
                  W_CHK_RDY_ST    = 3,
                  W_CHK_BVLD_ST   = 4;
  
  parameter       R_RESET_ST       = 0,
                  R_IDLE_ST        = 1,
                  R_CHK_ARRDY      = 2,
                  R_WAIT_RLAST_ST  = 3;

  reg [2:0]       cur_state;
  reg [2:0]       nxt_state;
  wire            data_avail_c;
  reg             write_datav_ltch;
  reg [1:0]       rd_cur_state;
  reg [1:0]       rd_nxt_state;
  reg             M_AXI_WREADY_1;
  reg             M_AXI_AWREADY_1;
  
//-----------------------------------------------------------------------------
// Current state generation. Registering the next state.
//-----------------------------------------------------------------------------
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      cur_state <= W_RESET_ST;
    else
      cur_state <= nxt_state;
  end
  
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      M_AXI_WREADY_1 <= 1'b0;
    else
      M_AXI_WREADY_1 <= M_AXI_WREADY;
  end
  
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      M_AXI_AWREADY_1 <= 1'b0;
    else
      M_AXI_AWREADY_1 <= M_AXI_AWREADY;
  end
  

//-----------------------------------------------------------------------------
// Combinatorial logic for next state genration
//-----------------------------------------------------------------------------
  always @ (cur_state or M_AXI_ARESETN or M_AXI_WREADY or
            M_AXI_BVALID or M_AXI_WVALID) begin
    case (cur_state)
      W_RESET_ST: begin                    // 0
        if (M_AXI_ARESETN == 1'b0)
          nxt_state = cur_state;
        else
          nxt_state = W_IDLE_ST;
          //nxt_state = W_GEN_VLD_ST;
      end

      //W_GEN_VLD_ST: begin
      W_IDLE_ST: begin                     // 1
        //nxt_state = W_CHK_RDY_ST;
        nxt_state = W_GEN_VLD_ST;
      end
	  
      W_GEN_VLD_ST: begin                 // 2
        nxt_state = W_CHK_RDY_ST;
      end

      W_CHK_RDY_ST: begin                 // 3 
        if (M_AXI_WREADY_1 == 1'b1 && M_AXI_WVALID == 1'b1)
          nxt_state = W_CHK_BVLD_ST;
        else
          nxt_state = cur_state;
      end

      W_CHK_BVLD_ST: begin                // 4
        if (M_AXI_BVALID == 1'b1)
          //nxt_state = W_RESET_ST;
          nxt_state = W_IDLE_ST;
        else
          nxt_state = cur_state;
      end

      default:
        nxt_state = W_RESET_ST;
    endcase
  end

//-----------------------------------------------------------------------------
// Driving the AXI master write signals
//-----------------------------------------------------------------------------
  assign M_AXI_AWADDR   = write_addr_i;
  //assign M_AXI_AWVALID  = write_addrv_i;  //   added this signal on 19th jan
  assign write_bresp_o  = M_AXI_BRESP;
  assign write_bvalid_o = M_AXI_BVALID;
//-----------------------------------------------------------------------------
// Logic that generate write address valid. Generate whenever there is a write
// start signals and the FSM is IDLE. Goes low on detection of awready
//-----------------------------------------------------------------------------
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      M_AXI_AWVALID <= 1'b0;	  
    //else if (cur_state == W_IDLE_ST )
    //else if (cur_state == W_GEN_VLD_ST && write_addrv_i == 1'b1)
    else if (write_addrv_i == 1'b1)
	//if (write_addrv_i == 1'b1)  //    added this signal on 19th jan
      M_AXI_AWVALID <= 1'b1; 
     // M_AXI_AWVALID <= write_addrv_i;     //added this signal on 20th jan 
    else if (M_AXI_AWREADY_1 == 1'b1 || (cur_state == W_CHK_BVLD_ST && M_AXI_BVALID == 1'b1))
      M_AXI_AWVALID <= 1'b0;
  end
//-----------------------------------------------------------------------------
  assign data_avail_c = write_datav_i | write_datav_ltch;
//-----------------------------------------------------------------------------
// Latching the write data valid. It is generated on write data valid pulse and
// the previous write data is not yet accepted
//-----------------------------------------------------------------------------
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      write_datav_ltch <= 1'b0;
    else if (write_datav_i && M_AXI_WVALID && !M_AXI_WREADY)
      write_datav_ltch <= 1'b1;
    else if (M_AXI_WREADY)
      write_datav_ltch <= 1'b0;
  end

//-----------------------------------------------------------------------------
// Generation of wvalid. It is generated on GEN_VLD_ST. It is keep asserted until
// next write data is available. de-asserted on acception of current write data
// and no next write data is available
//-----------------------------------------------------------------------------
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      M_AXI_WVALID <= 1'b0;
    //else if (cur_state == W_GEN_VLD_ST ||
            // (cur_state == W_CHK_RDY_ST && data_avail_c == 1'b1))
       else if (data_avail_c == 1'b1)
      M_AXI_WVALID <= 1'b1;
    else if (cur_state == W_CHK_RDY_ST && M_AXI_WREADY_1 == 1'b1)
      M_AXI_WVALID <= 1'b0;
  end
  
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      M_AXI_WDATA <= 128'd0;
    else if ((cur_state == W_GEN_VLD_ST ) ||
             ((cur_state == W_CHK_RDY_ST && data_avail_c == 1'b1) && 
              ((M_AXI_WVALID == 1'b0) || (M_AXI_WVALID == 1'b1 && M_AXI_WREADY == 1'b1)))
            )
      M_AXI_WDATA <= write_data_i;
  end

  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      M_AXI_WSTRB <= 16'd0;
    else if ((cur_state == W_GEN_VLD_ST ) ||
             ((cur_state == W_CHK_RDY_ST && data_avail_c == 1'b1) && 
              ((M_AXI_WVALID == 1'b0) || (M_AXI_WVALID == 1'b1 && M_AXI_WREADY == 1'b1)))
            )
      M_AXI_WSTRB <= write_strb_i;
  end
   
  //assign M_AXI_BREADY = (cur_state ==W_IDLE_ST)? 1'b1 : 1'b0;     // changed by mani on 21st jan
  assign M_AXI_BREADY = (cur_state ==W_CHK_BVLD_ST)? 1'b1 : 1'b0;  
//-----------------------------------------------------------------------------
// Current state generation for AXI master read
//-----------------------------------------------------------------------------
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      rd_cur_state <= R_RESET_ST;
    else
      rd_cur_state <= rd_nxt_state;
  end

//-----------------------------------------------------------------------------
// Next state generation for AXI master read
//-----------------------------------------------------------------------------
  always @ (*) begin
    case (rd_cur_state)
      R_RESET_ST: begin
        if (M_AXI_ARESETN == 1'b1)
          rd_nxt_state = R_IDLE_ST;
        else
          rd_nxt_state = rd_cur_state;
      end

      R_IDLE_ST: begin
        if (read_start_i == 1'b1)
          rd_nxt_state = R_CHK_ARRDY;
        else
          rd_nxt_state = rd_cur_state;
      end

      R_CHK_ARRDY: begin
        if (M_AXI_ARREADY == 1'b1)
          rd_nxt_state = R_WAIT_RLAST_ST;
        else
          rd_nxt_state = rd_cur_state;
      end

      R_WAIT_RLAST_ST: begin
        //if (M_AXI_RREADY == 1'b1)  
        if (M_AXI_RVALID == 1'b1)  
          rd_nxt_state = R_IDLE_ST;
        else
          rd_nxt_state = rd_cur_state;   
      end

      default:
        rd_nxt_state = R_RESET_ST;

    endcase
  end

//-----------------------------------------------------------------------------
// Generation of read address valid
//-----------------------------------------------------------------------------
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      M_AXI_ARVALID <= 1'b0;
    else if (rd_cur_state == R_IDLE_ST && read_start_i == 1'b1)
      M_AXI_ARVALID <= 1'b1;
    else if (M_AXI_ARREADY == 1'b1)
      M_AXI_ARVALID <= 1'b0;
  end
//-----------------------------------------------------------------------------
// Generation of read ready. '1' by default.
//-----------------------------------------------------------------------------
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      M_AXI_RREADY <= 1'b1;
    else
      M_AXI_RREADY <= ~read_af_i;
  end
//-----------------------------------------------------------------------------
// Generation of read data valid
//-----------------------------------------------------------------------------
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      read_data_o <= 128'd0;
    else
      read_data_o <= M_AXI_RDATA;
  end
  
  always @ (posedge M_AXI_ACLK or negedge M_AXI_ARESETN) begin
    if (M_AXI_ARESETN == 1'b0)
      read_datav_o <= 1'b0;
    else if (rd_cur_state == R_WAIT_RLAST_ST && M_AXI_RVALID == 1'b1 && M_AXI_RREADY == 1'b1)
    //else if (rd_cur_state == R_IDLE_ST && M_AXI_RVALID == 1'b1 && M_AXI_RREADY == 1'b1)  // changed by mani on 22nd jan
    //else if (M_AXI_RVALID == 1'b1 && M_AXI_RREADY == 1'b1)    // changed by mani on 21st jan
      read_datav_o <= 1'b1;
    else
      read_datav_o <= 1'b0;
  end
//-----------------------------------------------------------------------------
  assign M_AXI_ARADDR    = read_addr_i;
  assign M_AXI_AWPROT = 3'h0;

endmodule
//-----------------------------------------------------------------------------